from collections import defaultdict

from pyramid.view import view_config

from cpswarehouse.starquery import CpsStarQuery as StarQuery
from cpswarehouse.models import YearDimension, SchoolDimension
from cpswarehouse.models import DBSession
from cpswarehouse.charts import YearOverYearChart, RacePieChart

from sqlalchemy import func
from sqlalchemy import and_

import docutils.core

@view_config(route_name="index",
             renderer="index.mako")
def index(request):
    """Homepage view."""
    
    years = list(StarQuery(func=func.sum).group_by_year().fetch_all())

    schools = DBSession.query(SchoolDimension).filter(and_(SchoolDimension.latitude != None, SchoolDimension.longitude != None))
    js = YearOverYearChart(years).get_js()

    return {'years': years,
            'schools': schools,
            'yearbyyear': js}


@view_config(route_name='schools_on_a_map',
             renderer='on_a_map.mako')
def schools_on_a_map(request):
    """View for finding a school on a map."""

    schools = DBSession.query(SchoolDimension).filter(and_(SchoolDimension.latitude != None,
                                                           SchoolDimension.longitude != None))

    return {'schools': schools}



@view_config(route_name="school_listing",
             renderer='schools/index.mako')
def school_listing(request):
    """School listing page.

    Returns a giant list of schools in alphabetical order keyed by
    first letter."""
    schools = DBSession.query(SchoolDimension).order_by(SchoolDimension.name)
    
    letters_to_schools = defaultdict(list)

    for school in schools:
        try:
            first_letter = school.name[0]
        except IndexError:
            continue
        letters_to_schools[first_letter].append(school)

    letters = letters_to_schools.keys()
    letters.sort()

    return {'letters': letters,
            'schools': letters_to_schools}


@view_config(route_name="school_detail",
             renderer='schools/detail.mako')
def school_detail(request):
    """School detail page."""
    school = request.matchdict['school']

    school_obj = DBSession.query(SchoolDimension).\
                 filter(SchoolDimension.name == school).one()

    starquery = StarQuery()
    years = StarQuery(func=func.sum).\
        where_school_is(school_obj.id).\
        group_by_year().\
        fetch_all()
    years = list(years)

    return {'school': school_obj,
            'year_query': years,
            'year_chart': YearOverYearChart(years).get_js()}


@view_config(route_name="school_detail_by_year",
             renderer='schools/detail_one_year.mako')
def school_detail_by_year(request):
    """School detail page drilled down to a specific year."""
    school = request.matchdict['school']
    year = request.matchdict['year']
    
    school_obj = DBSession.query(SchoolDimension).filter(SchoolDimension.school == school).one()

    starquery = StarQuery()
    years = starquery.select_race(func=func.sum).\
        select_year().\
        select_school().\
        where_school_is(school_obj.id).\
        where_year_is(year).\
        group_by_year().\
        fetch_all()
    years = list(years)
    assert(len(years) == 1)
    year = years[0]

    pie_chart = RacePieChart(asian = year.asian,
                             black = year.black,
                             hispanic = year.hispanic,
                             nativeamerican = year.nativeamerican,
                             white = year.white)

    starquery = StarQuery()
    grades = starquery.select_race().\
        select_year().\
        select_grade().\
        select_school().\
        where_school_is(school_obj.id).\
        where_year_is(year.year).\
        fetch_all()

    return {'school': school_obj,
            'year': year,
            'pie_chart': pie_chart,
            'grades': list(grades)}


@view_config(route_name="year_listing",
             renderer='years/index.mako')
def year_listing(request):
    """Year listing page."""
    
    racial_facts = StarQuery(func=func.sum).\
        group_by_year().\
        fetch_all()
    racial_facts = list(racial_facts)
    
    return {'racial_facts': racial_facts,
            'year_chart': YearOverYearChart(racial_facts).get_js()}


@view_config(route_name="year_detail",
             renderer='years/detail.mako')
def year_detail(request):
    """Year detail page."""
    year = request.matchdict['year']
    
    racial_facts = StarQuery(func=func.sum).\
        where_year_is(year).\
        group_by_year().\
        fetch_all()
    racial_facts = list(racial_facts)
    race = racial_facts[0]

    pie_chart = RacePieChart(asian = race.asian,
                             black = race.black,
                             hispanic = race.hispanic,
                             nativeamerican = race.nativeamerican,
                             white = race.white)

    return {'year': race.year,
            'racial_facts': racial_facts,
            'pie_chart': pie_chart}


@view_config(route_name="what_is_this",
             renderer='static/what_is_this.mako')
def what_is_this(request):
    """The 'what is this' page.

    Only here to render a static template.
    """
    return {}


@view_config(route_name="dont_scrape_me",
             renderer='static/dont_scrape_me.mako')
def dont_scrape_me(request):
    """The 'don't scrape me' page.

    Only here to render a static template.
    """
    return {}


@view_config(route_name="get_involved",
             renderer='static/get_involved.mako')
def get_involved(request):
    """The 'get involved' page.

    Only here to render a static template.
    """
    return {}


FORMAT_DOC = """
%(body_pre_docinfo)s
%(docinfo)s
%(body)s
"""

@view_config(route_name="tutorial",
             renderer='doc.mako')
def rest_doc(request):
    """The documentation page.  This renders doc/tutorial.txt (a ReST
    document) using docutils and spits it out to the page.

    TODO Just reformat this and use sphinx."""

    text = open('docs/tutorial.txt').read()
    html_dict = docutils.core.publish_parts(text, writer_name='html')

    markup = FORMAT_DOC % html_dict

    return {'request': request, 'markup': markup }
